package cn.cdutetc.library.service.impl;

import cn.cdutetc.library.entity.dto.*;
import cn.cdutetc.library.entity.pojo.Book;
import cn.cdutetc.library.entity.pojo.Borrow;
import cn.cdutetc.library.entity.pojo.Payment;
import cn.cdutetc.library.entity.pojo.User;
import cn.cdutetc.library.mapper.BookMapper;
import cn.cdutetc.library.mapper.BorrowMapper;
import cn.cdutetc.library.mapper.PaymentMapper;
import cn.cdutetc.library.mapper.UserMapper;
import cn.cdutetc.library.service.StatisticsService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 统计服务实现类
 */
@Service
public class StatisticsServiceImpl implements StatisticsService {
    
    @Autowired
    private UserMapper userMapper;
    
    @Autowired
    private BookMapper bookMapper;
    
    @Autowired
    private BorrowMapper borrowMapper;
    
    @Autowired
    private PaymentMapper paymentMapper;
    
    @Autowired
    private cn.cdutetc.library.mapper.BookCategoryMapper bookCategoryMapper;
    
    @Autowired
    private cn.cdutetc.library.mapper.FeeRecordMapper feeRecordMapper;
    
    @Autowired
    private cn.cdutetc.library.mapper.BookItemMapper bookItemMapper;
    
    @Override
    public DashboardStatsDTO getDashboardStats(LocalDate startDate, LocalDate endDate) {
        DashboardStatsDTO stats = new DashboardStatsDTO();
        
        try {
            // 基础统计数据 - 显示所有数据
            stats.setTotalUsers(userMapper.selectCount(null));
            stats.setTotalBooks(bookMapper.selectCount(null));
            stats.setTotalBorrows(borrowMapper.selectCount(null));
            
            // 逾期借阅数
            QueryWrapper<Borrow> overdueWrapper = new QueryWrapper<>();
            overdueWrapper.eq("status", "overdue");
            stats.setOverdueBorrows(borrowMapper.selectCount(overdueWrapper));
            
            // 今日借阅数
            QueryWrapper<Borrow> todayBorrowWrapper = new QueryWrapper<>();
            todayBorrowWrapper.ge("borrow_date", LocalDate.now().atStartOfDay());
            todayBorrowWrapper.lt("borrow_date", LocalDate.now().plusDays(1).atStartOfDay());
            stats.setTodayBorrows(borrowMapper.selectCount(todayBorrowWrapper));
            
            // 今日归还数
            QueryWrapper<Borrow> todayReturnWrapper = new QueryWrapper<>();
            todayReturnWrapper.ge("return_date", LocalDate.now().atStartOfDay());
            todayReturnWrapper.lt("return_date", LocalDate.now().plusDays(1).atStartOfDay());
            stats.setTodayReturns(borrowMapper.selectCount(todayReturnWrapper));
            
            // 财务数据 - 显示所有数据
            QueryWrapper<Payment> paidWrapper = new QueryWrapper<>();
            paidWrapper.eq("status", "paid");
            List<Payment> paidPayments = paymentMapper.selectList(paidWrapper);
            
            BigDecimal totalIncome = paidPayments.stream()
                    .map(Payment::getAmount)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            stats.setTotalIncome(totalIncome);
            
            // 本月收入
            QueryWrapper<Payment> monthlyWrapper = new QueryWrapper<>();
            monthlyWrapper.eq("status", "paid");
            monthlyWrapper.ge("payment_time", LocalDate.now().withDayOfMonth(1).atStartOfDay());
            List<Payment> monthlyPayments = paymentMapper.selectList(monthlyWrapper);
            
            BigDecimal monthlyIncome = monthlyPayments.stream()
                    .map(Payment::getAmount)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            stats.setMonthlyIncome(monthlyIncome);
            
            // 今日收入
            QueryWrapper<Payment> todayIncomeWrapper = new QueryWrapper<>();
            todayIncomeWrapper.eq("status", "paid");
            todayIncomeWrapper.ge("payment_time", LocalDate.now().atStartOfDay());
            todayIncomeWrapper.lt("payment_time", LocalDate.now().plusDays(1).atStartOfDay());
            List<Payment> todayPayments = paymentMapper.selectList(todayIncomeWrapper);
            
            BigDecimal todayIncome = todayPayments.stream()
                    .map(Payment::getAmount)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            stats.setTodayIncome(todayIncome);
            
            // 获取各种统计数据 - 显示最近30天数据
            try {
                stats.setBorrowTrend(getBorrowTrend(null, null, 30));
            } catch (Exception e) {
                System.err.println("获取借阅趋势数据时出现异常: " + e.getMessage());
                e.printStackTrace();
            }
            
            try {
                stats.setCategoryStats(getCategoryStats());
            } catch (Exception e) {
                System.err.println("获取分类统计数据时出现异常: " + e.getMessage());
                e.printStackTrace();
            }
            
            try {
                stats.setFinancialTrend(getFinancialTrend(null, null, 30));
            } catch (Exception e) {
                System.err.println("获取财务趋势数据时出现异常: " + e.getMessage());
                e.printStackTrace();
            }
            
            try {
                stats.setPopularBooks(getPopularBooks(10));
            } catch (Exception e) {
                System.err.println("获取热门图书数据时出现异常: " + e.getMessage());
                e.printStackTrace();
            }
            
            try {
                stats.setActiveUsers(getActiveUsers(10));
            } catch (Exception e) {
                System.err.println("获取活跃用户数据时出现异常: " + e.getMessage());
                e.printStackTrace();
            }
            
        } catch (Exception e) {
            System.err.println("获取仪表盘统计数据时出现异常: " + e.getMessage());
            e.printStackTrace();
        }
        
        return stats;
    }
    
    @Override
    public FinancialStatsDTO getFinancialStats(LocalDate startDate, LocalDate endDate) {
        FinancialStatsDTO stats = new FinancialStatsDTO();
        
        QueryWrapper<Payment> wrapper = new QueryWrapper<>();
        wrapper.eq("status", "paid");
        if (startDate != null) {
            wrapper.ge("payment_time", startDate.atStartOfDay());
        }
        if (endDate != null) {
            wrapper.le("payment_time", endDate.plusDays(1).atStartOfDay());
        }
        
        List<Payment> payments = paymentMapper.selectList(wrapper);
        
        // 计算总收入
        BigDecimal totalIncome = payments.stream()
                .map(Payment::getAmount)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        stats.setTotalIncome(totalIncome);
        
        // 按支付方式统计
        Map<String, BigDecimal> paymentMethodMap = new HashMap<>();
        payments.forEach(payment -> {
            String method = payment.getPaymentType();
            paymentMethodMap.merge(method, payment.getAmount(), BigDecimal::add);
        });
        
        List<ChartDataDTO> paymentMethodStats = new ArrayList<>();
        paymentMethodMap.forEach((method, amount) -> {
            paymentMethodStats.add(new ChartDataDTO(method, amount));
        });
        stats.setPaymentMethodStats(paymentMethodStats);
        
        // 按费用类型统计
        Map<String, BigDecimal> feeTypeMap = new HashMap<>();
        payments.forEach(payment -> {
            // 从关联的费用记录中获取费用类型
            QueryWrapper<cn.cdutetc.library.entity.pojo.FeeRecord> feeWrapper = new QueryWrapper<>();
            feeWrapper.eq("fee_id", payment.getFeeId());
            List<cn.cdutetc.library.entity.pojo.FeeRecord> feeRecords = feeRecordMapper.selectList(feeWrapper);
            
            if (!feeRecords.isEmpty()) {
                String feeType = feeRecords.get(0).getFeeType();
                feeTypeMap.merge(feeType, payment.getAmount(), BigDecimal::add);
            }
        });
        
        List<ChartDataDTO> feeTypeStats = new ArrayList<>();
        feeTypeMap.forEach((type, amount) -> {
            feeTypeStats.add(new ChartDataDTO(type, amount));
        });
        stats.setFeeTypeStats(feeTypeStats);
        
        // 计算本月收入
        QueryWrapper<Payment> monthlyWrapper = new QueryWrapper<>();
        monthlyWrapper.eq("status", "paid");
        monthlyWrapper.ge("payment_time", LocalDate.now().withDayOfMonth(1).atStartOfDay());
        List<Payment> monthlyPayments = paymentMapper.selectList(monthlyWrapper);
        BigDecimal monthlyIncome = monthlyPayments.stream()
                .map(Payment::getAmount)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        stats.setMonthlyIncome(monthlyIncome);
        
        // 计算今日收入
        QueryWrapper<Payment> todayWrapper = new QueryWrapper<>();
        todayWrapper.eq("status", "paid");
        todayWrapper.ge("payment_time", LocalDate.now().atStartOfDay());
        todayWrapper.lt("payment_time", LocalDate.now().plusDays(1).atStartOfDay());
        List<Payment> todayPayments = paymentMapper.selectList(todayWrapper);
        BigDecimal todayIncome = todayPayments.stream()
                .map(Payment::getAmount)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        stats.setTodayIncome(todayIncome);
        
        // 计算逾期费收入
        BigDecimal overdueIncome = BigDecimal.ZERO;
        for (Payment payment : payments) {
            QueryWrapper<cn.cdutetc.library.entity.pojo.FeeRecord> feeWrapper = new QueryWrapper<>();
            feeWrapper.eq("fee_id", payment.getFeeId());
            List<cn.cdutetc.library.entity.pojo.FeeRecord> feeRecords = feeRecordMapper.selectList(feeWrapper);
            if (!feeRecords.isEmpty() && "overdue_fee".equals(feeRecords.get(0).getFeeType())) {
                overdueIncome = overdueIncome.add(payment.getAmount());
            }
        }
        stats.setOverdueIncome(overdueIncome);
        
        // 计算损坏费收入
        BigDecimal damageIncome = BigDecimal.ZERO;
        for (Payment payment : payments) {
            QueryWrapper<cn.cdutetc.library.entity.pojo.FeeRecord> feeWrapper = new QueryWrapper<>();
            feeWrapper.eq("fee_id", payment.getFeeId());
            List<cn.cdutetc.library.entity.pojo.FeeRecord> feeRecords = feeRecordMapper.selectList(feeWrapper);
            if (!feeRecords.isEmpty() && "damage_fee".equals(feeRecords.get(0).getFeeType())) {
                damageIncome = damageIncome.add(payment.getAmount());
            }
        }
        stats.setDamageIncome(damageIncome);
        
        // 计算丢失费收入
        BigDecimal lossIncome = BigDecimal.ZERO;
        for (Payment payment : payments) {
            QueryWrapper<cn.cdutetc.library.entity.pojo.FeeRecord> feeWrapper = new QueryWrapper<>();
            feeWrapper.eq("fee_id", payment.getFeeId());
            List<cn.cdutetc.library.entity.pojo.FeeRecord> feeRecords = feeRecordMapper.selectList(feeWrapper);
            if (!feeRecords.isEmpty() && "loss_fee".equals(feeRecords.get(0).getFeeType())) {
                lossIncome = lossIncome.add(payment.getAmount());
            }
        }
        stats.setLossIncome(lossIncome);
        
        // 获取趋势数据
        stats.setIncomeTrend(getFinancialTrend(startDate, endDate, 30));
        
        return stats;
    }
    
    @Override
    public List<ChartDataDTO> getBorrowTrend(LocalDate startDate, LocalDate endDate, Integer days) {
        List<ChartDataDTO> trendData = new ArrayList<>();
        
        // 确定日期范围
        LocalDate actualStartDate;
        LocalDate actualEndDate;
        
        if (startDate != null && endDate != null) {
            // 使用指定的日期范围
            actualStartDate = startDate;
            actualEndDate = endDate;
        } else {
            // 使用默认天数
            int defaultDays = (days != null) ? days : 7;
            actualEndDate = LocalDate.now();
            actualStartDate = actualEndDate.minusDays(defaultDays - 1);
        }
        
        // 生成日期范围内的每一天
        LocalDate currentDate = actualStartDate;
        while (!currentDate.isAfter(actualEndDate)) {
            LocalDateTime startOfDay = currentDate.atStartOfDay();
            LocalDateTime endOfDay = currentDate.plusDays(1).atStartOfDay();
            
            QueryWrapper<Borrow> wrapper = new QueryWrapper<>();
            wrapper.ge("borrow_date", startOfDay);
            wrapper.lt("borrow_date", endOfDay);
            
            Long count = borrowMapper.selectCount(wrapper);
            trendData.add(new ChartDataDTO(
                currentDate.format(DateTimeFormatter.ofPattern("MM-dd")),
                count,
                currentDate.toString()
            ));
            
            currentDate = currentDate.plusDays(1);
        }
        
        return trendData;
    }
    
    @Override
    public List<ChartDataDTO> getCategoryStats() {
        List<ChartDataDTO> categoryStats = new ArrayList<>();
        
        // 查询所有分类
        List<cn.cdutetc.library.entity.pojo.BookCategory> categories = bookCategoryMapper.selectList(null);
        
        // 为每个分类统计图书数量
        for (cn.cdutetc.library.entity.pojo.BookCategory category : categories) {
            QueryWrapper<cn.cdutetc.library.entity.pojo.Book> bookWrapper = new QueryWrapper<>();
            bookWrapper.eq("category_id", category.getCategoryId());
            Long bookCount = bookMapper.selectCount(bookWrapper);
            categoryStats.add(new ChartDataDTO(category.getCategoryName(), bookCount));
        }
        
        return categoryStats;
    }
    
    @Override
    public List<ChartDataDTO> getFinancialTrend(LocalDate startDate, LocalDate endDate, Integer days) {
        List<ChartDataDTO> trendData = new ArrayList<>();
        
        // 确定日期范围
        LocalDate actualStartDate;
        LocalDate actualEndDate;
        
        if (startDate != null && endDate != null) {
            // 使用指定的日期范围
            actualStartDate = startDate;
            actualEndDate = endDate;
        } else {
            // 使用默认天数
            int defaultDays = (days != null) ? days : 30;
            actualEndDate = LocalDate.now();
            actualStartDate = actualEndDate.minusDays(defaultDays - 1);
        }
        
        // 生成日期范围内的每一天
        LocalDate currentDate = actualStartDate;
        while (!currentDate.isAfter(actualEndDate)) {
            LocalDateTime startOfDay = currentDate.atStartOfDay();
            LocalDateTime endOfDay = currentDate.plusDays(1).atStartOfDay();
            
            QueryWrapper<Payment> wrapper = new QueryWrapper<>();
            wrapper.eq("status", "paid");
            wrapper.ge("payment_time", startOfDay);
            wrapper.lt("payment_time", endOfDay);
            
            List<Payment> payments = paymentMapper.selectList(wrapper);
            BigDecimal dailyIncome = payments.stream()
                    .map(Payment::getAmount)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            
            trendData.add(new ChartDataDTO(
                currentDate.format(DateTimeFormatter.ofPattern("MM-dd")),
                dailyIncome,
                currentDate.toString()
            ));
            
            currentDate = currentDate.plusDays(1);
        }
        
        return trendData;
    }
    
    @Override
    public List<BookRankDTO> getPopularBooks(Integer limit) {
        List<BookRankDTO> popularBooks = new ArrayList<>();
        
        try {
            // 查询所有图书及其借阅次数
            List<cn.cdutetc.library.entity.pojo.Book> books = bookMapper.selectList(null);
            
            for (cn.cdutetc.library.entity.pojo.Book book : books) {
                // 统计每本书的借阅次数 - 需要通过book_item表关联
                // 先查询这本书的所有单本图书
                QueryWrapper<cn.cdutetc.library.entity.pojo.BookItem> itemWrapper = new QueryWrapper<>();
                itemWrapper.eq("book_id", book.getBookId());
                List<cn.cdutetc.library.entity.pojo.BookItem> bookItems = bookItemMapper.selectList(itemWrapper);
                
                Long borrowCount = 0L;
                for (cn.cdutetc.library.entity.pojo.BookItem item : bookItems) {
                    // 统计每个单本图书的借阅次数
                    QueryWrapper<Borrow> borrowWrapper = new QueryWrapper<>();
                    borrowWrapper.eq("item_id", item.getItemId());
                    Long itemBorrowCount = borrowMapper.selectCount(borrowWrapper);
                    borrowCount += itemBorrowCount;
                }
                
                // 获取分类名称
                String categoryName = "未知分类";
                if (book.getCategoryId() != null) {
                    cn.cdutetc.library.entity.pojo.BookCategory category = bookCategoryMapper.selectById(book.getCategoryId());
                    if (category != null) {
                        categoryName = category.getCategoryName();
                    }
                }
                
                BookRankDTO bookRank = new BookRankDTO();
                bookRank.setBookId(book.getBookId());
                bookRank.setBookName(book.getBookName());
                bookRank.setIsbn(book.getIsbn());
                bookRank.setAuthor(book.getAuthor());
                bookRank.setBorrowCount(borrowCount);
                bookRank.setBorrowRate(book.getTotalCopies() > 0 ? (double) borrowCount / book.getTotalCopies() : 0.0);
                bookRank.setCategoryName(categoryName);
                
                popularBooks.add(bookRank);
            }
            
            // 按借阅次数降序排序
            popularBooks.sort((a, b) -> Long.compare(b.getBorrowCount(), a.getBorrowCount()));
            
            // 限制返回数量
            if (limit != null && limit > 0 && popularBooks.size() > limit) {
                return popularBooks.subList(0, limit);
            }
        } catch (Exception e) {
            // 如果出现异常，返回空列表
            System.err.println("获取热门图书排行时出现异常: " + e.getMessage());
            e.printStackTrace();
        }
        
        return popularBooks;
    }
    
    @Override
    public List<UserRankDTO> getActiveUsers(Integer limit) {
        List<UserRankDTO> activeUsers = new ArrayList<>();
        
        try {
            // 查询所有用户
            List<User> users = userMapper.selectList(null);
            
            for (User user : users) {
                // 统计用户的借阅次数
                QueryWrapper<Borrow> borrowWrapper = new QueryWrapper<>();
                borrowWrapper.eq("user_id", user.getUserId());
                Long borrowCount = borrowMapper.selectCount(borrowWrapper);
                
                // 计算借阅总天数
                List<Borrow> userBorrows = borrowMapper.selectList(borrowWrapper);
                Long totalBorrowDays = 0L;
                Long overdueCount = 0L;
                
                for (Borrow borrow : userBorrows) {
                    if (borrow.getBorrowDate() != null) {
                        LocalDateTime endDate = (borrow.getReturnDate() != null) ? 
                            borrow.getReturnDate() : LocalDateTime.now();
                        long days = java.time.Duration.between(borrow.getBorrowDate(), endDate).toDays();
                        totalBorrowDays += days;
                    }
                    
                    // 统计逾期次数
                    if ("overdue".equals(borrow.getStatus())) {
                        overdueCount++;
                    }
                }
                
                UserRankDTO userRank = new UserRankDTO();
                userRank.setUserId(user.getUserId());
                userRank.setUsername(user.getUsername());
                userRank.setRealName(user.getRealName());
                userRank.setBorrowCount(borrowCount);
                userRank.setBorrowDays(totalBorrowDays);
                userRank.setOverdueCount(overdueCount);
                userRank.setRole(user.getRole());
                
                activeUsers.add(userRank);
            }
            
            // 按借阅次数降序排序
            activeUsers.sort((a, b) -> Long.compare(b.getBorrowCount(), a.getBorrowCount()));
            
            // 限制返回数量
            if (limit != null && limit > 0 && activeUsers.size() > limit) {
                return activeUsers.subList(0, limit);
            }
            
        } catch (Exception e) {
            System.err.println("获取活跃用户排行时出现异常: " + e.getMessage());
            e.printStackTrace();
        }
        
        return activeUsers;
    }
    
    @Override
    public List<ChartDataDTO> getBorrowStatusStats() {
        List<ChartDataDTO> statusStats = new ArrayList<>();
        
        QueryWrapper<Borrow> borrowingWrapper = new QueryWrapper<>();
        borrowingWrapper.eq("status", "borrowing");
        statusStats.add(new ChartDataDTO("借阅中", borrowMapper.selectCount(borrowingWrapper)));
        
        QueryWrapper<Borrow> returnedWrapper = new QueryWrapper<>();
        returnedWrapper.eq("status", "returned");
        statusStats.add(new ChartDataDTO("已归还", borrowMapper.selectCount(returnedWrapper)));
        
        QueryWrapper<Borrow> overdueWrapper = new QueryWrapper<>();
        overdueWrapper.eq("status", "overdue");
        statusStats.add(new ChartDataDTO("逾期", borrowMapper.selectCount(overdueWrapper)));
        
        return statusStats;
    }
    
    @Override
    public List<ChartDataDTO> getUserRoleStats() {
        List<ChartDataDTO> roleStats = new ArrayList<>();
        
        QueryWrapper<User> adminWrapper = new QueryWrapper<>();
        adminWrapper.eq("role", "system_admin");
        roleStats.add(new ChartDataDTO("系统管理员", userMapper.selectCount(adminWrapper)));
        
        QueryWrapper<User> librarianWrapper = new QueryWrapper<>();
        librarianWrapper.eq("role", "book_admin");
        roleStats.add(new ChartDataDTO("图书管理员", userMapper.selectCount(librarianWrapper)));
        
        QueryWrapper<User> userWrapper = new QueryWrapper<>();
        userWrapper.eq("role", "normal_user");
        roleStats.add(new ChartDataDTO("普通用户", userMapper.selectCount(userWrapper)));
        
        return roleStats;
    }
    
    @Override
    public Long getNewUsersCount() {
        try {
            // 统计最近7天新增的用户数量
            QueryWrapper<User> wrapper = new QueryWrapper<>();
            wrapper.ge("create_time", LocalDateTime.now().minusDays(7));
            return userMapper.selectCount(wrapper);
        } catch (Exception e) {
            System.err.println("获取新增用户数量时出现异常: " + e.getMessage());
            e.printStackTrace();
            return 0L;
        }
    }
    
    @Override
    public Long getActiveUsersCount() {
        try {
            // 统计最近7天有借阅记录的用户数量
            LocalDateTime startDate = LocalDateTime.now().minusDays(7);
            return borrowMapper.selectActiveUsersCount(startDate);
        } catch (Exception e) {
            System.err.println("获取活跃用户数量时出现异常: " + e.getMessage());
            e.printStackTrace();
            return 0L;
        }
    }
}
